#include <math.h>
#include <iostream>
#include <string>
#include <functional>

using std::cout;
using std::endl;
using std::string;
using std::bind;
using std::function;

//面向对象的四大特征：抽象、封装、继承、多态
//面向对象的思想与基于对象的思想都是需要掌握的，有些时候
//还可以混用
//面向对象的思想：虚函数 + 继承
//基于对象的思想：std::bind + std::function
class Figure
{
public:
    using DisplayCallback = function<void()>;
    using AreaCallback = function<double()>;

    //C语言中借助函数指针调用回调函数，在C++中借助std::bind
    //+ std::function调用回调函数，使用思路都是先注册后执行
    //回调函数:先注册后执行
    void setDisplayCallback(DisplayCallback &&cb)
    {
        _displayCallback = std::move(cb);//移动赋值
    }

    void setAreaCallback(AreaCallback &&cb)
    {
        _areaCallback = std::move(cb);//移动赋值
    }

    void handleDisplayCallback() const
    {
        if(_displayCallback)
        {
            _displayCallback();//回调
        }
    }

    double handleAreaCallback()  const
    {
        if(_areaCallback)
        {
            return _areaCallback();//回调
        }
        else
        {
            return 0.0;
        }
    }

public:
    DisplayCallback _displayCallback;//数据成员
    AreaCallback _areaCallback;//数据成员
};

class Rectangle
{
public:
    Rectangle(double len, double wid)
    : _length(len)
    , _width(wid)
    {}

    void display(int x) const 
    {
        cout << "Rectangle ";
    }

    double area() const 
    {
        return _length * _width;
    }

    ~Rectangle()
    {

    }

private:
    double _length;
    double _width;
};

class Circle
{
public:
    Circle(double rad)
    : _radius(rad)
    {}
 
    void show() const 
    {
        cout << "Circle ";
    }

    double showArea() const 
    {
        return 3.14 * _radius * _radius; 
    }

    ~Circle()
    {
    }

private:
    double _radius;
};

class Triangle
{
public:
    Triangle(double a,double b,double c)
    : _x(a)
    , _y(b)
    , _z(c)
    {}
  
    void print() const 
    {
        cout << "Triangle ";
    }

    //海伦公式
    double printArea() const 
    {
        double c = (_x + _y + _z)/2;
        return sqrt(c * (c - _x) * (c - _y) * (c - _z));
    }

    ~Triangle()
    {
    }
private:
    double _x;
    double _y;
    double _z;
};

void func(const Figure &fig)
{
    fig.handleDisplayCallback();
    cout << "的面积是：" << fig.handleAreaCallback() << endl;
}

int main(void)
{
    Rectangle rectangle(10, 20);
    Circle circle(10);
    Triangle triangle(6, 8, 10);

    Figure fig;
    //绑定的就是Rectangle
    /* function<void()> f = bind(&Rectangle::display, &rectangle, 10); */
    /* fig.setDisplayCallback(std::move(f)); */
    fig.setDisplayCallback(bind(&Rectangle::display, &rectangle, 10));
    fig.setAreaCallback(bind(&Rectangle::area, &rectangle));
    func(fig);

    //绑定的就是Circle
    fig.setDisplayCallback(bind(&Circle::show, &circle));
    fig.setAreaCallback(bind(&Circle::showArea, &circle));
    func(fig);

    //绑定的就是Triangle
    fig.setDisplayCallback(bind(&Triangle::print, &triangle));
    fig.setAreaCallback(bind(&Triangle::printArea, &triangle));
    func(fig);

    return 0;
}
